<template>
  <div class="image-preview-wrapper">
    <!-- 触发预览的元素 -->
    <div class="preview-trigger" @click.stop="showPreview">
      <slot />
      <div class="preview-overlay" v-if="showOverlay">
        <EyeOutlined class="preview-icon" />
      </div>
    </div>

    <!-- 预览模态框 -->
    <a-modal
      v-model:open="visible"
      :title="modalTitle"
      :footer="null"
      width="500px"
      centered
      class="image-preview-modal"
      @after-close="handleModalClose"
    >
      <div class="image-preview-container">
        <!-- 加载动画 -->
        <div v-show="loading" class="loading-container">
          <a-spin size="large" tip="图片加载中...">
            <div class="loading-placeholder"></div>
          </a-spin>
        </div>

        <!-- 图片 -->
        <img
          :src="imageUrl"
          :alt="alt"
          class="preview-image"
          :class="{ 'image-loaded': !loading }"
          @load="handleImageLoad"
          @error="handleImageError"
          v-show="!loading"
          ref="previewImageRef"
        />
      </div>
    </a-modal>
  </div>
</template>

<script lang="ts" setup>
import { ref, computed } from 'vue'
import { message } from 'ant-design-vue'
import { EyeOutlined } from '@ant-design/icons-vue'

// Props
interface Props {
  imageUrl?: string
  alt?: string
  title?: string
  showOverlay?: boolean
}

const props = withDefaults(defineProps<Props>(), {
  imageUrl: '',
  alt: '图片',
  title: '图片预览',
  showOverlay: true,
})

// 响应式状态
const visible = ref(false)
const loading = ref(false)
const previewImageRef = ref<HTMLImageElement>()

// 计算属性
const modalTitle = computed(() => props.title)

// 显示预览
const showPreview = () => {
  if (!props.imageUrl) {
    message.warning('没有可预览的图片')
    return
  }

  // 检查图片是否已经缓存
  const img = new Image()
  img.onload = () => {
    // 图片已缓存，无需显示加载状态
    loading.value = false
  }
  img.onerror = () => {
    // 图片加载失败，显示加载状态等待重新加载
    loading.value = true
  }
  img.src = props.imageUrl

  // 如果图片已经完成加载（complete为true），则无需显示加载状态
  if (img.complete && img.naturalHeight !== 0) {
    loading.value = false
  } else {
    loading.value = true
  }

  visible.value = true
}

// 图片加载完成
const handleImageLoad = () => {
  loading.value = false
}

// 处理图片加载错误
const handleImageError = (event: Event) => {
  loading.value = false
  const img = event.target as HTMLImageElement
  img.src =
    ''
  message.error('图片加载失败')
}

// 模态框关闭后重置状态
const handleModalClose = () => {
  loading.value = false
}
</script>

<style scoped>
/* 预览触发器 */
.image-preview-wrapper {
  display: inline-block;
}

.preview-trigger {
  position: relative;
  cursor: pointer;
  display: inline-block;
}

/* 悬浮覆盖层 */
.preview-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(108, 92, 231, 0.8);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: all 0.3s ease;
}

.preview-trigger:hover .preview-overlay {
  opacity: 1;
}

.preview-icon {
  color: white;
  font-size: 16px;
}

/* 模态框样式 */
.image-preview-modal :deep(.ant-modal-header) {
  background: linear-gradient(135deg, #6c5ce7, #5a4fcf);
  border-radius: 8px 8px 0 0;
}

.image-preview-modal :deep(.ant-modal-title) {
  color: white;
  font-weight: 600;
}

.image-preview-container {
  text-align: center;
  padding: 20px;
  min-height: 200px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* 加载动画容器 */
.loading-container {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 200px;
}

.loading-placeholder {
  width: 300px;
  height: 200px;
  background: linear-gradient(90deg, #f0f0f0 25%, rgba(240, 240, 240, 0.5) 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: shimmer 1.5s infinite;
  border-radius: 8px;
}

@keyframes shimmer {
  0% {
    background-position: -200% 0;
  }
  100% {
    background-position: 200% 0;
  }
}

/* 图片样式 */
.preview-image {
  max-width: 100%;
  max-height: 400px;
  border-radius: 8px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
  transition: all 0.3s ease;
  opacity: 0;
}

.preview-image.image-loaded {
  opacity: 1;
  animation: fadeIn 0.3s ease-in-out;
}

@keyframes fadeIn {
  from {
    opacity: 0;
    transform: scale(0.95);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

.preview-image:hover {
  transform: scale(1.02);
}
</style>
